package com.bsoft.gol.hcs.specialist.service.impl;

import com.alibaba.fastjson.JSON;
import com.bsoft.gol.hcs.enumcase.*;
import com.bsoft.gol.hcs.followup.dao.FusAfterHosRecordDAO;
import com.bsoft.gol.hcs.specialist.bean.request.ProduceFusAfterPlanRequest;
import com.bsoft.gol.hcs.specialist.bean.response.FactorData;
import com.bsoft.gol.hcs.specialist.dao.*;
import com.bsoft.gol.hcs.specialist.entity.*;
import com.bsoft.gol.hcs.specialist.service.IFollowUpCommonService;
import com.bsoft.gol.hcs.specialist.service.IProduceFusAfterPlanService;
import com.bsoft.gol.hcs.utils.BaseRespUtil;
import com.bsoft.gol.hcs.utils.CommonUtils;
import com.bsoft.gol.hcs.utils.Utils;
import com.bsoft.gol.hcs.visitrecord.dao.VrInpatientVisitRecordDAO;
import com.bsoft.gol.hcs.visitrecord.dao.VrOutpatientVisitRecordDAO;
import com.bsoft.gol.hcs.visitrecord.entity.VrInpatientVisitRecord;
import ctd.controller.exception.ControllerException;
import ctd.util.KeyGenerator;
import ctd.util.annotation.RpcService;
import hcn.base.VrOutpatientVisitRecord;
import hcn.enums.ItemTypeEnum;
import hcn.util.BaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static com.bsoft.gol.hcs.enumcase.VisitRecordEnum.*;

/**
 * @author tongtp
 * @version v0.1
 * @package specialist.service.impl
 * @className ProduceFusAfterPlanServiceImpl
 * @description 生成院后随访计划服务
 * @create 2022-05-27 11:28
 **/
@Service
public class ProduceFusAfterPlanServiceImpl implements IProduceFusAfterPlanService {

	private final static Logger logger = LoggerFactory.getLogger(ProduceFusAfterPlanServiceImpl.class);

	@Value("${admin_user_id}")
	private String adminUserId;
	@Autowired
	private FollowUpRouteDAO followUpRouteDAO;
	@Autowired
	private FollowUpRouteDetailDAO followUpRouteDetailDAO;
	@Autowired
	private FollowUpRouteDetailContentDAO followUpRouteDetailContentDAO;
	@Autowired
	private FollowUpRouteDetailFactorDAO followUpRouteDetailFactorDAO;
	@Autowired
	private FollowUpRouteDetailFormDAO followUpRouteDetailFormDAO;
	@Autowired
	private IFollowUpCommonService followUpCommonService;
	@Autowired
	VrInpatientVisitRecordDAO vrInpatientVisitRecordDAO;
	@Autowired
	VrOutpatientVisitRecordDAO vrOutpatientVisitRecordDAO;
	@Autowired
	private FusAfterPlanProduceRecordDAO fusAfterPlanProduceRecordDAO;
	@Autowired
	private FusAfterHosRecordDAO fusAfterHosRecordDAO;
	@Autowired
	private FollowUpPathRouteDAO followUpPathRouteDAO;
	@Autowired
	private FollowPlanDAO followPlanDAO;
	@Autowired
	private FollowUpPathRouteExplandDAO followUpPathRouteExplandDAO;
	@Autowired
	private FusAfterRequisitionRecordDAO fusAfterRequisitionRecordDAO;
	@Autowired
	private FusAfterHealthEducationDAO fusAfterHealthEducationDAO;
	@Autowired
	private FusAfterHosRecordContentDAO fusAfterHosRecordContentDAO;
	@Autowired
	private FusAfterRecommendDeptDAO fusAfterRecommendDeptDAO;

	/**
	 * 根据医生在医生站的设置生成院后随访计划
	 *
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 10:27
	 */
	@Override
	public void produceFusAfterPlanByDocSetting() throws ControllerException {
		logger.info("produceFusAfterPlanByDocSetting start");
		List<FollowUpPathRouteEntity> followUpPathRouteList = followUpPathRouteDAO.queryNeedProduceSetting();
		if (!CollectionUtils.isEmpty(followUpPathRouteList)) {
			for (FollowUpPathRouteEntity followUpPathRoute :
					followUpPathRouteList) {
				long fusPathRouteId = followUpPathRoute.getFusPathRouteId();
				String visitNo = followUpPathRoute.getVisitNo();
				String organizationId = followUpPathRoute.getOrganizationId();
				//先查询对应的就诊类型记录有没有同步过来，没有同步过来的先跳过
				//source 类别 1,门诊2住院
				switch (getEnumByKey(followUpPathRoute.getSource())) {
					case OUTPATIENT_VISIT_RECORD:
						VrOutpatientVisitRecord vrOutpatientVisitRecord =
								vrOutpatientVisitRecordDAO.getByVisitNo(visitNo,
										organizationId);
						if (vrOutpatientVisitRecord != null) {
							saveFusAfterPlanByDocSetting(followUpPathRoute, fusPathRouteId, vrOutpatientVisitRecord,
									null);
						} else {
							logger.info("fusPathRouteId:{},visitNo:{},organizationId:{},就诊记录未同步过来," +
											"跳过执行根据医生在医生站的设置生成随访计划", fusPathRouteId,
									visitNo,
									organizationId);
						}
						break;
					case INPATIENT_VISIT_RECORD:
						VrInpatientVisitRecord vrInpatientVisitRecord =
								vrInpatientVisitRecordDAO.getByVisitNo(visitNo,
										organizationId);
						if (vrInpatientVisitRecord != null) {
							saveFusAfterPlanByDocSetting(followUpPathRoute, fusPathRouteId, null,
									vrInpatientVisitRecord);
						} else {
							logger.info("fusPathRouteId:{},visitNo:{},organizationId:{},就诊记录未同步过来," +
											"跳过执行根据医生在医生站的设置生成随访计划", fusPathRouteId,
									visitNo,
									organizationId);
						}
						break;
					default:
						break;
				}
			}
		}
		logger.info("produceFusAfterPlanByDocSetting end");
	}

	/**
	 * 根据医生在医生站的设置保存院后随访计划
	 *
	 * @param followUpPathRoute
	 * @param fusPathRouteId
	 * @param vrOutpatientVisitRecord
	 * @param vrInpatientVisitRecord
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 13:35
	 */
	private void saveFusAfterPlanByDocSetting(FollowUpPathRouteEntity followUpPathRoute, long fusPathRouteId,
											  VrOutpatientVisitRecord vrOutpatientVisitRecord,
											  VrInpatientVisitRecord vrInpatientVisitRecord) {
		FollowUpRoute followUpRoute = followUpRouteDAO.get(followUpPathRoute.getRouteId());
		List<FollowPlanEntity> followPlans =
				followPlanDAO.findFplByFusPathRouteId(fusPathRouteId);
		//是否通知患者，0不通知，1通知
		//医生站设置的都是不通知
		Byte isNotify = (byte) 0;
		//复核计划 0否 1是 默认为0
		//医生站设置的都是不复核
		String checkPlan = "0";
		Date recordTime;
		if (!CollectionUtils.isEmpty(followPlans)) {
			for (FollowPlanEntity followPlan :
					followPlans) {
				FusAfterHosRecord fusAfterHosRecord = new FusAfterHosRecord();
				//设置计划生成类型
				fusAfterHosRecord.setPlanProduceType(PlanProduceTypeEnum.HAND.getType());
				if (vrOutpatientVisitRecord != null) {
					//如果就诊结束时间为空就取就诊开始时间
					if (CommonUtils.isNull(vrOutpatientVisitRecord.getEndTime())) {
						recordTime = vrOutpatientVisitRecord.getStartTime();
					} else {
						recordTime = vrOutpatientVisitRecord.getEndTime();
					}
					//门诊就诊记录填充fusAfterHosRecord属性值
					setFusAfterHosRecord(vrOutpatientVisitRecord, recordTime, fusAfterHosRecord);
				} else {
					//住院记录填充fusAfterHosRecord属性值
					recordTime = vrInpatientVisitRecord.getDischargeTime();
					setFusAfterHosRecord(vrInpatientVisitRecord, fusAfterHosRecord);
				}
				//计算随访计划开始时间
				//时间节点长度
				Integer timeNodeSize = followPlan.getTimeNodeSize();
				//时间节点长度单位，1日 2周 3月
				Byte timeNodeSizeUnit = followPlan.getTimeNodeSizeUnit();
				//时间间隔-天数
				Integer timeInterval = 0;
				switch (timeNodeSizeUnit) {
					case 1:
						timeInterval = timeNodeSize;
						break;
					case 2:
						timeInterval = timeNodeSize * 7;
						break;
					case 3:
						timeInterval = timeNodeSize * 30;
						break;
					default:
						break;
				}
				Calendar instance = Calendar.getInstance();
				instance.setTime(recordTime);
				instance.add(Calendar.DAY_OF_YEAR, timeInterval);
				Date startPlanTime = instance.getTime();
				String fusAfterHosRecordId = KeyGenerator.randomGenerate();
				//执行保存随访计划
				doSaveFusAfterHosRecord(followUpRoute, adminUserId, null, fusAfterHosRecord, null
						, fusAfterHosRecordId,
						startPlanTime, followPlan.getRouteDetailType(), isNotify, checkPlan);
				List<FollowUpPathRouteExplandEntity> explands =
						followUpPathRouteExplandDAO.findFupreByFollowPlanId(followPlan.getFollowPlanId());
				for (FollowUpPathRouteExplandEntity expland :
						explands) {
					//content_type 1表示随访表单2表示健康宣教
					if ("1".equals(expland.getContentType())) {
						FusAfterRequisitionRecord requisitionRecord =
								new FusAfterRequisitionRecord();
						requisitionRecord.setFormId(Utils.getUUID());
						requisitionRecord.setRecordId(fusAfterHosRecordId);
						requisitionRecord.setCreateId(adminUserId);
						requisitionRecord.setCreateDt(new Date());
						requisitionRecord.setQuestionnaireId(expland.getFormEducationId());
						requisitionRecord.setQuestionnaireName(expland.getFormEducationName());
						fusAfterRequisitionRecordDAO.save(requisitionRecord);
					}
					if ("2".equals(expland.getContentType())) {
						FusAfterHealthEducation fusAfterHealthEducation =
								new FusAfterHealthEducation();
						fusAfterHealthEducation.setId(Utils.getUUID());
						fusAfterHealthEducation.setRecordId(fusAfterHosRecordId);
						fusAfterHealthEducation.setCreateDt(new Date());
						fusAfterHealthEducation.setEducationId(Long.valueOf(expland.getFormEducationId()));
						fusAfterHealthEducation.setEducationName(expland.getFormEducationName());
						fusAfterHealthEducationDAO.save(fusAfterHealthEducation);
					}
				}

			}
		}
		//没有计划，直接设置为已生成&&存在计划的，生成计划后也设置为已生成
		followUpPathRoute.setStatus("1");
		followUpPathRouteDAO.update(followUpPathRoute);
	}

	/**
	 * 生成院后随访计划
	 *
	 * @param request
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/5/27 11:27
	 */
	@RpcService
	@Override
	public void produceFusAfterPlan(ProduceFusAfterPlanRequest request) throws ControllerException {
		logger.info("produceFusAfterPlan start");
		//查询对应随访大类启用状态的随访路径列表
		//随访大类类型 1-专病随访，2-院后随访，3-满意度随访
		List<FollowUpRoute> followUpRoutes =
				followUpRouteDAO.queryByFollowTypeAndStatus(FollowTypeEnum.FUS_AFTER.getType(),
						FollowUpRouteStatusEnum.ENABLE.getStatus());
		if (!CollectionUtils.isEmpty(followUpRoutes)) {
			for (FollowUpRoute followUpRoute :
					followUpRoutes) {
				doProduceExecutionList(followUpRoute, adminUserId);
			}
		}
		logger.info("produceFusAfterPlan end");
		return;
	}

	/**
	 * 生成院后随访计划
	 *
	 * @param followUpRoute
	 * @param operatorId
	 * @return org.atag.core.base.BaseResponse
	 * @throws
	 * @author tongtp
	 * @date 2022/5/27 13:51
	 */
	private BaseResponse doProduceExecutionList(FollowUpRoute followUpRoute, String operatorId) throws ControllerException {
		//查询随访路径子路径列表
		List<FollowUpRouteDetail> followUpRouteDetails =
				followUpRouteDetailDAO.queryByRouteId(followUpRoute.getRouteId());
		if (!CollectionUtils.isEmpty(followUpRouteDetails)) {
			for (FollowUpRouteDetail followUpRouteDetail :
					followUpRouteDetails) {
				handleFollowUpRouteDetail(followUpRoute, followUpRouteDetail, operatorId);
			}
		}
		return BaseRespUtil.setResultSuccess();
	}

	/**
	 * 处理随访路径详情
	 *
	 * @param followUpRouteDetail
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/5/27 13:55
	 */
	private void handleFollowUpRouteDetail(FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
										   String operatorId) throws ControllerException {
		//随访路径详情id
		Long routeDetailId = followUpRouteDetail.getRouteDetailId();
		//循环执行机制 0 不执行 1 执行
		Byte isLoopExecute = followUpRouteDetail.getIsLoopExecute();
		//查询随访路径详情因素
		//factorFlag因素类型
		List<FollowUpRouteDetailFactor> followUpRouteDetailFactors =
				followUpRouteDetailFactorDAO.queryByRouteDetailId(routeDetailId, FactorFlagEnum.START.getType());
		if (!CollectionUtils.isEmpty(followUpRouteDetailFactors)) {
			//遍历的所有因素依次执行筛选:
			//and相连的因素检索出来的数据求交集，遇到OR连接符时，把前面检索出来的数据集合保存，
			//后面检索出来的数据在遇到下一个OR连接符或者结束时与前面检索出来的数据集合求并集
			List<String> previousList = new ArrayList<>();
			//病人因素信息存储集合，key是病人id，value是按顺序存储的因素数据集合
			Map<String, List<FactorData>> patientInfoMap = new HashMap<>(256);
			//处理因素列表得到人员信息集合和因素数据集合
			followUpCommonService.handleFactorList(followUpRoute, isLoopExecute, followUpRouteDetailFactors,
					previousList, patientInfoMap);
			//去重
			if (!CollectionUtils.isEmpty(previousList)) {
				HashSet<String> h = new HashSet(previousList);
				previousList.clear();
				previousList.addAll(h);
			}
			if (CollectionUtils.isEmpty(previousList)) {
				logger.info("RouteDetailId:{},子路径没有检索到符合条件的人员数据", routeDetailId);
			} else {
				logger.info("RouteDetailId:{},子路径检索到符合条件的人员数据如下:{}", routeDetailId, JSON.toJSONString(previousList));
				//随访提前通知时间-天数
				Integer advanceNotifyDate = 1;
				//是否通知患者，0不通知，1通知
				if (followUpRouteDetail.getIsNotify() == (byte) 1) {
					advanceNotifyDate = followUpCommonService.getAdvanceNotifyDate(null, followUpRouteDetail,
							routeDetailId
							, advanceNotifyDate);
					if (advanceNotifyDate == null) {
						return;
					}
				}
				List<FollowUpRouteDetailForm> followUpRouteDetailForms =
						followUpRouteDetailFormDAO.queryByRouteDetailId(followUpRouteDetail.getRouteDetailId());
				List<FollowUpRouteDetailContent> followUpRouteDetailContents =
						followUpRouteDetailContentDAO.queryByRouteDetailId(followUpRouteDetail.getRouteDetailId());
				for (String patientId :
						previousList) {
					//根据就诊类型查询对应的就诊类型记录
					switch (getEnumByKey(followUpRoute.getVisitType())) {
						case OUTPATIENT_VISIT_RECORD:
							handleForOutpatient(followUpRoute, followUpRouteDetail, operatorId, routeDetailId,
									patientInfoMap,
									advanceNotifyDate, followUpRouteDetailForms, patientId, followUpRouteDetailContents);
							break;
						case INPATIENT_VISIT_RECORD:
							handleForInpatient(followUpRoute, followUpRouteDetail, operatorId, routeDetailId,
									patientInfoMap,
									advanceNotifyDate, followUpRouteDetailForms, patientId, followUpRouteDetailContents);
							break;
						case PHYSICAL_EXAMINATION_RECORDS:
							//todo 3.5.01迭代不实现
							break;
						default:
							break;
					}
				}
			}
		}
	}

	/**
	 * 处理住院记录
	 *
	 * @param followUpRoute
	 * @param followUpRouteDetail
	 * @param operatorId
	 * @param routeDetailId
	 * @param patientInfoMap
	 * @param advanceNotifyDate
	 * @param followUpRouteDetailForms
	 * @param patientId
	 * @param followUpRouteDetailContents
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/6 14:41
	 */
	private void handleForInpatient(FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
									String operatorId,
									Long routeDetailId, Map<String, List<FactorData>> patientInfoMap,
									Integer advanceNotifyDate
			, List<FollowUpRouteDetailForm> followUpRouteDetailForms, String patientId,
									List<FollowUpRouteDetailContent> followUpRouteDetailContents) throws ControllerException {
		VrInpatientVisitRecord vrInpatientVisitRecord =
				vrInpatientVisitRecordDAO.getByPatientIdAndLastOne(patientId, followUpRoute.getDepartmentId());
		if (Objects.isNull(vrInpatientVisitRecord)) {
			return;
		}
		//得到要生成随访计划的就诊类型记录之后，需要判断该子路径有没有给该就诊类型记录生成过。生成过则不用再生成了。
		FusAfterPlanProduceRecord fusAfterPlanProduceRecord =
				fusAfterPlanProduceRecordDAO.getByRouteDetailId(routeDetailId,
						vrInpatientVisitRecord.getOrganizationId(),
						INPATIENT_VISIT_RECORD.getType().intValue(),
						vrInpatientVisitRecord.getVisitNo());
		if (fusAfterPlanProduceRecord == null) {
			//院后随访有个医生站嵌入页面，医生站有设置的需要随访的，设置的那个路径下的所有子路径都不能再给改就诊记录生成随访计划；
			//设置的不需要随访的，这个就诊记录不生成任何院后随访计划
			FollowUpPathRouteEntity followUpPathRoute =
					followUpPathRouteDAO.getFuprByCardNoAndSource(vrInpatientVisitRecord.getOrganizationId(),
							vrInpatientVisitRecord.getVisitNo(),
							INPATIENT_VISIT_RECORD.getType());
			//是否跳过生成随访计划
			boolean isSkip = followUpPathRoute != null &&
					(followUpPathRoute.getFollowUpType() == (byte) 0 || followUpRoute.getRouteId().equals(followUpPathRoute.getRouteId()));
			if (isSkip) {
				logger.info("根据医生站嵌入设置不生成随访计划，跳过生成;vrInpatientVisitRecord:{}," +
								"followUpPathRoute:{}",
						JSON.toJSONString(vrInpatientVisitRecord),
						JSON.toJSONString(followUpPathRoute));
			} else {
				//生成随访计划
				//如果就诊结束时间为空就取就诊开始时间
				Date recordTime = vrInpatientVisitRecord.getDischargeTime();
				//保存随访计划（随访表单、健康宣教、推荐科室、复诊项目、监测范围等数据要一并保存，和随访计划id关联）
				FusAfterHosRecord fusAfterHosRecord = new FusAfterHosRecord();
				//住院记录填充fusAfterHosRecord属性值
				setFusAfterHosRecord(vrInpatientVisitRecord, fusAfterHosRecord);
				saveFusAfterHosRecordAndOther(followUpRoute, followUpRouteDetail, operatorId,
						patientInfoMap,
						advanceNotifyDate, followUpRouteDetailForms, patientId, recordTime,
						fusAfterHosRecord,followUpRouteDetailContents);
			}
		} else {
			logger.info("该子路径给该就诊类型记录生成过随访计划，跳过生成;vrInpatientVisitRecord:{}," +
							"fusAfterPlanProduceRecord:{}",
					JSON.toJSONString(vrInpatientVisitRecord),
					JSON.toJSONString(fusAfterPlanProduceRecord));
		}
	}

	/**
	 * 住院记录填充fusAfterHosRecord属性值
	 *
	 * @param vrInpatientVisitRecord
	 * @param fusAfterHosRecord
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 14:10
	 */
	private void setFusAfterHosRecord(VrInpatientVisitRecord vrInpatientVisitRecord,
									  FusAfterHosRecord fusAfterHosRecord) {
		fusAfterHosRecord.setOrganizationId(vrInpatientVisitRecord.getOrganizationId());
		fusAfterHosRecord.setOrganizationName(vrInpatientVisitRecord.getOrganizationName());
		fusAfterHosRecord.setDepartmentId(vrInpatientVisitRecord.getDepartmentId());
		fusAfterHosRecord.setDepartmentName(vrInpatientVisitRecord.getDepartmentName());
		fusAfterHosRecord.setDoctorId(vrInpatientVisitRecord.getDoctorId());
		fusAfterHosRecord.setDoctorName(vrInpatientVisitRecord.getDoctorName());
		fusAfterHosRecord.setPatientId(vrInpatientVisitRecord.getPatientId());
		fusAfterHosRecord.setCardType(vrInpatientVisitRecord.getCardType());
		fusAfterHosRecord.setCardNumber(vrInpatientVisitRecord.getCardNumber());
		fusAfterHosRecord.setPatientName(vrInpatientVisitRecord.getPatientName());
		fusAfterHosRecord.setPatientSex(vrInpatientVisitRecord.getPatientSex());
		if (CommonUtils.isNotNull(vrInpatientVisitRecord.getPatientAge())) {
			fusAfterHosRecord.setPatientAge(vrInpatientVisitRecord.getPatientAge().intValue());
		}
		fusAfterHosRecord.setTelephone(vrInpatientVisitRecord.getTelephone());
		fusAfterHosRecord.setAddress(vrInpatientVisitRecord.getAddress());
		fusAfterHosRecord.setPatientMedicalCardNumber(vrInpatientVisitRecord.getPatientMedicalCardNumber());
		fusAfterHosRecord.setPatientMedicalCardType(vrInpatientVisitRecord.getPatientMedicalCardType());
		fusAfterHosRecord.setPatientType(INPATIENT_VISIT_RECORD.getType().intValue());
		if (CommonUtils.isNull(vrInpatientVisitRecord.getInHospitalRecordNumber())) {
			fusAfterHosRecord.setInpatientNumber(vrInpatientVisitRecord.getInHospitalRecordCode());
		} else {
			fusAfterHosRecord.setInpatientNumber(vrInpatientVisitRecord.getInHospitalRecordNumber());
		}
		fusAfterHosRecord.setVisitNo(vrInpatientVisitRecord.getVisitNo());
		fusAfterHosRecord.setMedicalRecordNumber(vrInpatientVisitRecord.getMedicalRecordNumber());
		fusAfterHosRecord.setVisitTime(vrInpatientVisitRecord.getDischargeTime());
	}

	/**
	 * 处理门诊就诊记录
	 *
	 * @param followUpRoute
	 * @param followUpRouteDetail
	 * @param operatorId
	 * @param routeDetailId
	 * @param patientInfoMap
	 * @param advanceNotifyDate
	 * @param followUpRouteDetailForms
	 * @param patientId
	 * @param followUpRouteDetailContents
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/6 14:34
	 */
	private void handleForOutpatient(FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
									 String operatorId,
									 Long routeDetailId, Map<String, List<FactorData>> patientInfoMap,
									 Integer advanceNotifyDate
			, List<FollowUpRouteDetailForm> followUpRouteDetailForms, String patientId,
									 List<FollowUpRouteDetailContent> followUpRouteDetailContents) throws ControllerException {
		VrOutpatientVisitRecord vrOutpatientVisitRecord =
				vrOutpatientVisitRecordDAO.getByPatientIdAndLastOne(patientId, followUpRoute.getDepartmentId());
		if (Objects.isNull(vrOutpatientVisitRecord)) {
			return;
		}
		//得到要生成随访计划的就诊类型记录之后，需要判断该子路径有没有给该就诊类型记录生成过。生成过则不用再生成了。
		FusAfterPlanProduceRecord fusAfterPlanProduceRecord =
				fusAfterPlanProduceRecordDAO.getByRouteDetailId(routeDetailId,
						vrOutpatientVisitRecord.getOrganizationId(),
						OUTPATIENT_VISIT_RECORD.getType().intValue(),
						vrOutpatientVisitRecord.getVisitNo());
		if (fusAfterPlanProduceRecord == null) {
			//院后随访有个医生站嵌入页面，医生站有设置的需要随访的，设置的那个路径下的所有子路径都不能再给改就诊记录生成随访计划；
			//设置的不需要随访的，这个就诊记录不生成任何院后随访计划
			FollowUpPathRouteEntity followUpPathRoute =
					followUpPathRouteDAO.getFuprByCardNoAndSource(vrOutpatientVisitRecord.getOrganizationId(),
							vrOutpatientVisitRecord.getVisitNo(),
							OUTPATIENT_VISIT_RECORD.getType());
			//是否跳过生成随访计划
			boolean isSkip = followUpPathRoute != null &&
					(followUpPathRoute.getFollowUpType() == (byte) 0 || followUpRoute.getRouteId().equals(followUpPathRoute.getRouteId()));
			if (isSkip) {
				logger.info("根据医生站嵌入设置不生成随访计划，跳过生成;vrOutpatientVisitRecord:{}," +
								"followUpPathRoute:{}",
						JSON.toJSONString(vrOutpatientVisitRecord),
						JSON.toJSONString(followUpPathRoute));
			} else {
				//生成随访计划
				//如果就诊结束时间为空就取就诊开始时间
				Date recordTime;
				if (CommonUtils.isNull(vrOutpatientVisitRecord.getEndTime())) {
					recordTime = vrOutpatientVisitRecord.getStartTime();
				} else {
					recordTime = vrOutpatientVisitRecord.getEndTime();
				}
				//保存随访计划（随访表单、健康宣教、推荐科室、复诊项目、监测范围等数据要一并保存，和随访计划id关联）
				FusAfterHosRecord fusAfterHosRecord = new FusAfterHosRecord();
				//门诊就诊记录填充fusAfterHosRecord属性值
				setFusAfterHosRecord(vrOutpatientVisitRecord, recordTime, fusAfterHosRecord);
				saveFusAfterHosRecordAndOther(followUpRoute, followUpRouteDetail, operatorId,
						patientInfoMap,
						advanceNotifyDate, followUpRouteDetailForms, patientId, recordTime,
						fusAfterHosRecord,followUpRouteDetailContents);
			}
		} else {
			logger.info("该子路径给该就诊类型记录生成过随访计划，跳过生成;vrOutpatientVisitRecord:{}," +
							"fusAfterPlanProduceRecord:{}",
					JSON.toJSONString(vrOutpatientVisitRecord),
					JSON.toJSONString(fusAfterPlanProduceRecord));
		}
	}

	/**
	 * 门诊就诊记录填充fusAfterHosRecord属性值
	 *
	 * @param vrOutpatientVisitRecord
	 * @param recordTime
	 * @param fusAfterHosRecord
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 14:12
	 */
	private void setFusAfterHosRecord(VrOutpatientVisitRecord vrOutpatientVisitRecord, Date recordTime,
									  FusAfterHosRecord fusAfterHosRecord) {
		fusAfterHosRecord.setOrganizationId(vrOutpatientVisitRecord.getOrganizationId());
		fusAfterHosRecord.setOrganizationName(vrOutpatientVisitRecord.getOrganizationName());
		fusAfterHosRecord.setDepartmentId(vrOutpatientVisitRecord.getDepartmentId());
		fusAfterHosRecord.setDepartmentName(vrOutpatientVisitRecord.getDepartmentName());
		fusAfterHosRecord.setDoctorId(vrOutpatientVisitRecord.getDoctorId());
		fusAfterHosRecord.setDoctorName(vrOutpatientVisitRecord.getDoctorName());
		fusAfterHosRecord.setPatientId(vrOutpatientVisitRecord.getPatientId());
		fusAfterHosRecord.setCardType(vrOutpatientVisitRecord.getCardType());
		fusAfterHosRecord.setCardNumber(vrOutpatientVisitRecord.getCardNumber());
		fusAfterHosRecord.setPatientName(vrOutpatientVisitRecord.getPatientName());
		fusAfterHosRecord.setPatientSex(vrOutpatientVisitRecord.getPatientSex());
		if (CommonUtils.isNotNull(vrOutpatientVisitRecord.getPatientAge())) {
			fusAfterHosRecord.setPatientAge(vrOutpatientVisitRecord.getPatientAge().intValue());
		}
		fusAfterHosRecord.setTelephone(vrOutpatientVisitRecord.getTelephone());
		fusAfterHosRecord.setAddress(vrOutpatientVisitRecord.getAddress());
		fusAfterHosRecord.setPatientMedicalCardNumber(vrOutpatientVisitRecord.getPatientMedicalCardNumber());
		fusAfterHosRecord.setPatientMedicalCardType(vrOutpatientVisitRecord.getPatientMedicalCardType());
		fusAfterHosRecord.setPatientType(OUTPATIENT_VISIT_RECORD.getType().intValue());
		fusAfterHosRecord.setOutpatientNumber(vrOutpatientVisitRecord.getPatientMedicalCardNumber());
		fusAfterHosRecord.setVisitNo(vrOutpatientVisitRecord.getVisitNo());
		fusAfterHosRecord.setVisitTime(recordTime);
	}

	/**
	 * 保存院后随访计划、随访表单,健康宣教等、随访计划生产记录、因素使用记录
	 *
	 * @param followUpRoute
	 * @param followUpRouteDetail
	 * @param operatorId
	 * @param patientInfoMap
	 * @param advanceNotifyDate
	 * @param followUpRouteDetailForms
	 * @param patientId
	 * @param recordTime
	 * @param fusAfterHosRecord
	 * @param followUpRouteDetailContents
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/6 13:59
	 */
	private void saveFusAfterHosRecordAndOther(FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
											   String operatorId,
											   Map<String, List<FactorData>> patientInfoMap, Integer advanceNotifyDate,
											   List<FollowUpRouteDetailForm> followUpRouteDetailForms,
											   String patientId, Date recordTime,
											   FusAfterHosRecord fusAfterHosRecord,
											   List<FollowUpRouteDetailContent> followUpRouteDetailContents) throws ControllerException {
		//随访大类类型
		String followType = followUpRoute.getFollowType();
		Long routeDetailId = followUpRouteDetail.getRouteDetailId();
		List<FactorData> factorDataList = patientInfoMap.get(patientId);
		String fusAfterHosRecordId = KeyGenerator.randomGenerate();
		Date now = new Date();
		//设置计划生成类型
		fusAfterHosRecord.setPlanProduceType(PlanProduceTypeEnum.AUTO.getType());
		//保存院后随访计划
		saveFusAfterHosRecord(followUpRoute, followUpRouteDetail, operatorId, advanceNotifyDate, recordTime,
				fusAfterHosRecord,
				followType, routeDetailId, factorDataList, fusAfterHosRecordId);
		//保存随访表单,健康宣教,推荐科室,复诊项目
		saveFormAndEducationAndDept(operatorId, followUpRouteDetailForms, fusAfterHosRecordId, now);
		//保存复诊项目等随访内容
		saveFusAfterHosRecordContent(followUpRouteDetailContents, fusAfterHosRecordId);
		//保存院后随访计划生成记录
		saveFusAfterPlanProduceRecord(followUpRouteDetail, fusAfterHosRecord, routeDetailId, now);
		//院后随访计划生成，需要更新对应就诊类型记录的计划次数
		updateFusAfterPlanTimes(followUpRoute.getVisitType(), fusAfterHosRecord.getVisitNo(),
				fusAfterHosRecord.getOrganizationId());
		//保存因素数据使用记录
		followUpCommonService.saveFusFactorDataRecord(followType, routeDetailId, factorDataList, null,
				fusAfterHosRecordId);
	}

	/**
	 * 保存复诊项目等随访内容
	 *
	 * @param followUpRouteDetailContents
	 * @param fusAfterHosRecordId
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 18:45
	 */
	private void saveFusAfterHosRecordContent(List<FollowUpRouteDetailContent> followUpRouteDetailContents,
											  String fusAfterHosRecordId) {
		if (!CollectionUtils.isEmpty(followUpRouteDetailContents)) {
			for (FollowUpRouteDetailContent followUpRouteDetailContent :
					followUpRouteDetailContents) {
				FusAfterHosRecordContent fusAfterHosRecordContent = new FusAfterHosRecordContent();
				fusAfterHosRecordContent.setId(Utils.getUUID());
				fusAfterHosRecordContent.setRecordId(fusAfterHosRecordId);
				fusAfterHosRecordContent.setIndexType(followUpRouteDetailContent.getIndexType());
				fusAfterHosRecordContent.setIndexClassifyId(followUpRouteDetailContent.getIndexClassifyId());
				fusAfterHosRecordContent.setIndexClassifyName(followUpRouteDetailContent.getIndexClassifyName());
				fusAfterHosRecordContent.setBusinessId(followUpRouteDetailContent.getBusinessId());
				fusAfterHosRecordContent.setBusinessName(followUpRouteDetailContent.getBusinessName());
				fusAfterHosRecordContent.setProjectDetails(followUpRouteDetailContent.getProjectDetails());
				fusAfterHosRecordContent.setFollowUpDetail(followUpRouteDetailContent.getFollowUpDetail());
				fusAfterHosRecordContentDAO.save(fusAfterHosRecordContent);
			}
		}
	}

	/**
	 * 保存随访表单,健康宣教,推荐科室
	 *
	 * @param operatorId
	 * @param followUpRouteDetailForms
	 * @param fusAfterHosRecordId
	 * @param now
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 18:36
	 */
	private void saveFormAndEducationAndDept(String operatorId, List<FollowUpRouteDetailForm> followUpRouteDetailForms,
											 String fusAfterHosRecordId, Date now) {
		if (!CollectionUtils.isEmpty(followUpRouteDetailForms)) {
			for (FollowUpRouteDetailForm followUpRouteDetailForm :
					followUpRouteDetailForms) {
				if (ItemTypeEnum.FORM.getType().equals(followUpRouteDetailForm.getItemType())) {
					FusAfterRequisitionRecord requisitionRecord =
							new FusAfterRequisitionRecord();
					requisitionRecord.setFormId(Utils.getUUID());
					requisitionRecord.setRecordId(fusAfterHosRecordId);
					requisitionRecord.setCreateId(operatorId);
					requisitionRecord.setCreateDt(now);
					requisitionRecord.setQuestionnaireId(followUpRouteDetailForm.getFormRecordId());
					requisitionRecord.setQuestionnaireName(followUpRouteDetailForm.getFormName());
					fusAfterRequisitionRecordDAO.save(requisitionRecord);
				}
				if (ItemTypeEnum.DEPT.getType().equals(followUpRouteDetailForm.getItemType())) {
					FusAfterRecommendDept fusAfterRecommendDept = new FusAfterRecommendDept();
					fusAfterRecommendDept.setId(Utils.getUUID());
					fusAfterRecommendDept.setRecordId(fusAfterHosRecordId);
					fusAfterRecommendDept.setOrganizationId(followUpRouteDetailForm.getOrganizationId());
					fusAfterRecommendDept.setDeptType(followUpRouteDetailForm.getDeptType());
					fusAfterRecommendDept.setParentDeptCode(followUpRouteDetailForm.getParentDeptCode());
					fusAfterRecommendDept.setParentDeptName(followUpRouteDetailForm.getParentDeptName());
					fusAfterRecommendDept.setDeptCode(followUpRouteDetailForm.getDeptCode());
					fusAfterRecommendDept.setDeptName(followUpRouteDetailForm.getDeptName());
					fusAfterRecommendDeptDAO.save(fusAfterRecommendDept);
				}
				if (ItemTypeEnum.EDUCATION.getType().equals(followUpRouteDetailForm.getItemType())) {
					FusAfterHealthEducation fusAfterHealthEducation =
							new FusAfterHealthEducation();
					fusAfterHealthEducation.setId(Utils.getUUID());
					fusAfterHealthEducation.setRecordId(fusAfterHosRecordId);
					fusAfterHealthEducation.setCreateDt(now);
					fusAfterHealthEducation.setEducationId(followUpRouteDetailForm.getEducationId());
					fusAfterHealthEducation.setEducationName(followUpRouteDetailForm.getEducationName());
					fusAfterHealthEducationDAO.save(fusAfterHealthEducation);
				}
			}
		}
	}

	/**
	 * 院后随访计划生成，需要更新对应就诊类型记录的计划次数
	 *
	 * @param visitType
	 * @param visitNo
	 * @param organizationId
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/7 19:54
	 */
	private void updateFusAfterPlanTimes(Byte visitType, String visitNo, String organizationId) {
		switch (getEnumByKey(visitType)) {
			case OUTPATIENT_VISIT_RECORD:
				vrOutpatientVisitRecordDAO.updateFusAfterPlanTimes(visitNo, organizationId);
				break;
			case INPATIENT_VISIT_RECORD:
				vrInpatientVisitRecordDAO.updateFusAfterPlanTimes(visitNo, organizationId);
				break;
			case PHYSICAL_EXAMINATION_RECORDS:
				//todo 3.5.01迭代不实现
				break;
			default:
				break;
		}
	}

	/**
	 * 保存院后随访计划
	 *
	 * @param followUpRoute
	 * @param followUpRouteDetail
	 * @param operatorId
	 * @param advanceNotifyDate
	 * @param recordTime
	 * @param fusAfterHosRecord
	 * @param followType
	 * @param routeDetailId
	 * @param factorDataList
	 * @param fusAfterHosRecordId
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/7 18:47
	 */
	private void saveFusAfterHosRecord(FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
									   String operatorId,
									   Integer advanceNotifyDate, Date recordTime, FusAfterHosRecord fusAfterHosRecord,
									   String followType, Long routeDetailId, List<FactorData> factorDataList,
									   String fusAfterHosRecordId) throws ControllerException {
		//计算随访计划开始时间-第一次随访计划的计划执行时间
		Date startPlanTime = followUpCommonService.getStartPlanTime(followUpRouteDetail,
				factorDataList,
				followType, null
				, recordTime);
		int routeDetailType = followUpRouteDetail.getRouteDetailType().intValue();
		Byte isNotify = followUpRouteDetail.getIsNotify();
		//复核计划 0否 1是 默认为0
		String checkPlan = followUpRoute.getCheckPlan();
		doSaveFusAfterHosRecord(followUpRoute, operatorId, advanceNotifyDate, fusAfterHosRecord, routeDetailId,
				fusAfterHosRecordId,
				startPlanTime, routeDetailType, isNotify, checkPlan);
	}

	/**
	 * 执行院后随访保存
	 *
	 * @param followUpRoute
	 * @param operatorId
	 * @param advanceNotifyDate
	 * @param fusAfterHosRecord
	 * @param routeDetailId
	 * @param fusAfterHosRecordId
	 * @param startPlanTime
	 * @param routeDetailType
	 * @param isNotify
	 * @param checkPlan
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/8 14:29
	 */
	private void doSaveFusAfterHosRecord(FollowUpRoute followUpRoute, String operatorId, Integer advanceNotifyDate,
										 FusAfterHosRecord fusAfterHosRecord, Long routeDetailId,
										 String fusAfterHosRecordId,
										 Date startPlanTime, int routeDetailType, Byte isNotify, String checkPlan) {
		if (CommonUtils.isNotNull(followUpRoute) && CommonUtils.isNotNull(followUpRoute.getTenantId())) {
			fusAfterHosRecord.setTenantId(followUpRoute.getTenantId());
		} else {
			fusAfterHosRecord.setTenantId(followUpCommonService.getTenantIdByOrgCode(fusAfterHosRecord.getOrganizationId()));
		}
		fusAfterHosRecord.setRouteDetailType(routeDetailType);
		fusAfterHosRecord.setPlanTime(startPlanTime);
		fusAfterHosRecord.setFollowUpStatus(FollowUpStatusEnum.READY.getStatus());
		fusAfterHosRecord.setCreateId(operatorId);
		fusAfterHosRecord.setCreateTime(new Date());
		if (CommonUtils.isNotNull(followUpRoute)) {
			fusAfterHosRecord.setRouteId(followUpRoute.getRouteId());
			fusAfterHosRecord.setRouteName(followUpRoute.getRouteName());
		}
		fusAfterHosRecord.setRouteDetailId(routeDetailId);
		fusAfterHosRecord.setReadFlag((byte) 0);
		fusAfterHosRecord.setNotifyFlag(isNotify);
		//是否通知患者，0不通知，1通知
		if (isNotify == (byte) 1) {
			Calendar advanceNotifyDateInstance = Calendar.getInstance();
			advanceNotifyDateInstance.setTime(startPlanTime);
			advanceNotifyDateInstance.add(Calendar.DAY_OF_YEAR, advanceNotifyDate);
			fusAfterHosRecord.setPlanNotifyDate(advanceNotifyDateInstance.getTime());
		}
		fusAfterHosRecord.setNotifyStatus(0);
		fusAfterHosRecord.setHangUpFlag(false);
		if (CommonUtils.isNotNull(checkPlan)) {
			fusAfterHosRecord.setAuditStatus(Integer.valueOf(checkPlan));
		}
		fusAfterHosRecord.setRecordId(fusAfterHosRecordId);
		fusAfterHosRecord.setDeptId(followUpCommonService.getDeptIdByLocalDeptId(fusAfterHosRecord.getOrganizationId()
				, fusAfterHosRecord.getDepartmentId()));

		boolean firstFollowUp = fusAfterHosRecordDAO.isFirstFollowUp(fusAfterHosRecord.getPatientId(), fusAfterHosRecord.getOrganizationId(), fusAfterHosRecord.getTenantId());
		if(firstFollowUp){
			fusAfterHosRecord.setFirstFlag(true);
		}
		fusAfterHosRecordDAO.insertSelective(fusAfterHosRecord);
	}

	/**
	 * 保存院后随访计划生成记录
	 *
	 * @param followUpRouteDetail
	 * @param fusAfterHosRecord
	 * @param routeDetailId
	 * @param now
	 * @return void
	 * @throws
	 * @author tongtp
	 * @date 2022/6/7 18:43
	 */
	private void saveFusAfterPlanProduceRecord(FollowUpRouteDetail followUpRouteDetail,
											   FusAfterHosRecord fusAfterHosRecord,
											   Long routeDetailId, Date now) {
		//保存随访计划生成记录
		FusAfterPlanProduceRecord fusAfterPlanProduceRecord =
				new FusAfterPlanProduceRecord();
		fusAfterPlanProduceRecord.setId(Utils.getUUID());
		fusAfterPlanProduceRecord.setPatientType(fusAfterHosRecord.getPatientType());
		fusAfterPlanProduceRecord.setOrganizationId(fusAfterHosRecord.getOrganizationId());
		fusAfterPlanProduceRecord.setVisitNo(fusAfterHosRecord.getVisitNo());
		fusAfterPlanProduceRecord.setRouteDetailId(routeDetailId);
		//状态：1 执行中 2 停止
		fusAfterPlanProduceRecord.setStatus(1);
		fusAfterPlanProduceRecord.setFollowUpFrequency(followUpRouteDetail.getFollowUpFrequency().intValue());
		fusAfterPlanProduceRecord.setStartTime(now);
		fusAfterPlanProduceRecord.setGmtCreate(now);
		fusAfterPlanProduceRecord.setGmtModified(now);
		fusAfterPlanProduceRecordDAO.save(fusAfterPlanProduceRecord);
	}


}
